package com.datang.litejvm.loader;

import com.datang.litejvm.clz.Class;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.List;


/**
 * @author: 顶风少年
 * @Description: 类加载器
 * @date: 13:54 2022/6/10
 **/
public class ClassLoader {

    /**
     * @author: 顶风少年
     * @Description: 存放环境变量
     * @date: 21:58 2022/6/8
     **/
    private List<String> clzPaths = new ArrayList<String>();


    /**
     * @author: 顶风少年
     * @Description: 添加环境变量 classPath
     * @date: 21:53 2022/6/8
     **/
    public void addClassPath(String path) {
        if (this.clzPaths.contains(path)) {
            return;
        }
        this.clzPaths.add(path);
    }


    /**
     * @author: 顶风少年
     * @Description: 返回classPath, 多个中间使用 ; 拼接
     * @date: 21:53 2022/6/8
     **/
    public String getClassPath() {
        return StringUtils.join(this.clzPaths, ";");
    }

    /**
     * @author: 顶风少年
     * @Description: 将classpath和className拼接获取类路径
     * @date: 21:53 2022/6/8
     **/
    public byte[] readBinaryCode(String className) {
        className = className.replace('.', File.separatorChar) + ".class";
        for (String path : this.clzPaths) {
            String clzFileName = path + File.separatorChar + className;
            byte[] codes = loadClassFile(clzFileName);
            if (codes != null) {
                return codes;
            }
        }
        return null;
    }

    /**
     * @author: 顶风少年
     * @Description: 根据类路径读取class文件
     * @date: 21:54 2022/6/8
     **/
    private byte[] loadClassFile(String clzFileName) {
        File f = new File(clzFileName);
        try {
            return IOUtils.toByteArray(new FileInputStream(f));
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * @author: 顶风少年
     * @Description: 解析class文件形成Class对象,在这里是形成ClassFile对象
     * @date: 13:55 2022/6/10
     **/
    public Class loadClass(String className) {
        byte[] codes = this.readBinaryCode(className);
        ClassParser parser = new ClassParser();
        return parser.parse(codes);
    }
}
